/**
 * h函数
 * @param {String} tag 标签名
 * @param {Object} prop 属性
 * @param {*} children 子元素
 * @returns {Object} 虚拟节点
 */
const h = (tag, props, children) => {
  return { tag, props, children };
};

/**
 * 挂载虚拟节点至指定元素
 * @param {Object} vnode 虚拟节点
 * @param {*} container 需要挂载的元素
 */
const mount = (vnode, container) => {
  // 创建真实的DOM，并且在vnode上保留el
  const el = (vnode.el = document.createElement(vnode.tag));

  // 处理props
  if (vnode.props) {
    for (const key in vnode.props) {
      const value = vnode.props[key];

      if (key.startsWith("on")) {
        // 事件监听判断
        el.addEventListener(key.slice(2).toLowerCase(), value);
      } else {
        el.setAttribute(key, value);
      }
    }
  }

  // 处理children
  if (vnode.children) {
    if (typeof vnode.children === "string") {
      el.textContent = vnode.children;
    } else {
      vnode.children.forEach((item) => {
        mount(item, el);
      });
    }
  }

  // 将el挂载到container上
  container.appendChild(el);
};

/**
 * 比较两个虚拟节点
 * @param {Object} n1 虚拟节点1
 * @param {Object} n2 虚拟节点2
 */
const patch = (n1, n2) => {
  if (n1.tag !== n2.tag) {
    const n1ElParent = n1.el.parentElement;
    n1ElParent.removeChild(n1.el);
    mount(n2, n1ElParent);
  } else {
    // 取出element对象，并且在n2中进行保存
    const el = (n2.el = n1.el);

    // 处理props
    const oldProps = n1.props || {};
    const newProps = n2.props || {};

    // 获取所有的newProps增加到el
    for (const key in newProps) {
      const oldValue = oldProps[key];
      const newValue = newProps[key];
      if (newValue !== oldValue) {
        if (key.startsWith("on")) {
          // 事件监听判断
          el.addEventListener(key.slice(2).toLowerCase(), newValue);
        } else {
          el.setAttribute(key, newValue);
        }
      }
    }

    // 删除旧的props
    for (const key in oldProps) {
      if (key.startsWith("on")) {
        // 事件监听判断
        const value = oldProps[key];
        el.removeEventListener(key.slice(2).toLowerCase(), value);
      }
      if (!(key in newProps)) {
        el.removeAttribute(key);
      }
    }

    // 处理children
    const oldChildren = n1.children || [];
    const newChildren = n2.children || [];

    if (typeof newChildren === "string") {
      // 情况1: newChildren是String
      if (typeof oldChildren === "string") {
        if (newChildren !== oldChildren) {
          el.textContent = newChildren;
        } else {
          el.innerHTML = newChildren;
        }
      }
    } else {
      // 情况2: newChildren是数组
      if (typeof oldChildren === "string") {
        el.innerHTML = "";
        newChildren.forEach((item) => {
          mount(item, el);
        });
      } else {
        // 前面有相同节点的原生进行path操作
        const commonLength = Math.min(oldChildren.length, newChildren.length);
        for (let i = 0; i < commonLength; i++) {
          patch(oldChildren[i], newChildren[i]);
        }

        // newChildren.length > oldChildren.length
        if (newChildren.length > oldChildren.length) {
          newChildren.slice(oldChildren.length).forEach((item) => {
            mount(item, el);
          });
        }

        // newChildren.length < oldChildren.length
        if (newChildren.length < oldChildren.length) {
          oldChildren.slice(newChildren.length).forEach((item) => {
            el.removeChild(child.el);
          });
        }
      }
    }
  }
};
